package com.apeli;

import com.apeli.model.*;
import lombok.SneakyThrows;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.*;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.Resource;
import org.springframework.core.metrics.StartupStep;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.StopWatch;

import java.beans.PropertyEditor;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.Executor;

@ComponentScan
@EnableAsync
public class SpringApplication {
    @SneakyThrows
    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringApplication.class);
//        System.out.println(context.getBean("user"));

        StopWatch stopWatch = new StopWatch("id");
        stopWatch.start("test");
        Thread.sleep(1000);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        // Todo 手动注册一个BeanDefinition
//        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition.setBeanClass(User.class);
//        beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
//        beanDefinition.setInitMethodName("init");
//        context.registerBeanDefinition("user",beanDefinition);
//        System.out.println(context.getBean("user"));

        // Todo 直接将某个类转化为BeanDefinition，可以解析该类上的注解

//        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
//        reader.register(User.class);
//        System.out.println(context.getBean("user"));

        // Todo ClassPathBeanDefinitionScanner 类扫描器，可以扫描包下面被@Component修饰的类

//        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
//        scanner.scan("com.apeli");
//        System.out.println(context.getBean("user"));

        // Todo BeanFactory 创建Bean的工厂
//        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition.setBeanClass(Order.class);
//        beanFactory.registerBeanDefinition("order", beanDefinition);
//        System.out.println(beanFactory.getBean("order"));

        // todo context 国际化
//        System.out.println(context.getMessage("aa", new Object[]{}, Locale.CHINESE));

        // Todo resource
//        Resource resource = context.getResource("file://D:\\idea\\file\\apeli-spring\\spring-core\\src\\main\\java\\com\\apeli\\model\\User.java");
//        System.out.println(resource.getFilename());
//        System.out.println(resource.getDescription());
//        System.out.println(resource.getURL());
//        Resource[] resources = context.getResources("classpath:com\\apeli\\model\\*.class");
//        for (Resource resource1 : resources) {
//            System.out.println(resource1.getFilename());
//        }

        // Todo 获取系统环境变量

//        Map<String, Object> systemEnvironment = context.getEnvironment().getSystemProperties();
//        for (Map.Entry<String, Object> entry : systemEnvironment.entrySet()) {
//            System.out.println(entry.getKey()+"======>"+entry.getValue());
//        }

        // Todo Spring监听器

//        context.publishEvent(new OrderApplicationListener.OrderEvent("resource","下单消息","1"));
//        System.out.println("contine ...");

        // spring 文本转对象
//        StringToUserEditor editor = new StringToUserEditor();
//        editor.setAsText("user");
//        System.out.println(editor.getValue());
//        System.out.println(context.getBean("order"));

//        DefaultConversionService conversionService = new DefaultConversionService();
//        conversionService.addConverter(new StringToOrderConvert());
//        Order value = conversionService.convert("1", Order.class);
//        System.out.println(value);

        // order注解
//        Order order = new Order();
//        User user = new User();
//        AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
//        List<Object> list = new ArrayList<>(Arrays.asList(user,order));
//        list.sort(comparator);
//        System.out.println(list);

        // spring 元数据

//        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
//        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.apeli.model.Order");
//
//        // 得到一个ClassMetadata，并获取了类名
//        ClassMetadata classMetadata = metadataReader.getClassMetadata();
//
//        System.out.println("类元数据："+classMetadata);
//
//        // 获取一个AnnotationMetadata，并获取类上的注解信息
//        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//        System.out.println(annotationMetadata.hasAnnotation("org.springframework.core.annotation.Order"));
//        for (String annotationType : annotationMetadata.getAnnotationTypes()) {
//            System.out.println("获取注解："+annotationType);
//        }
        Object apeLiBean = context.getBean("apeLiBean");
        System.out.println(apeLiBean);
    }

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        return messageSource;
    }

    @Bean
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor poolTE = new ThreadPoolTaskExecutor();
        // 设置线程池的数目
        poolTE.setCorePoolSize(10);
        poolTE.setMaxPoolSize(20);
        poolTE.setQueueCapacity(50);
        poolTE.initialize();
        return poolTE;
    }
//    @Bean(initMethod = "init",destroyMethod = "after")
    public Employee employee() {
        return new Employee();
    }

    @Bean
    public CustomEditorConfigurer customEditorConfigurer() {
        CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
        Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();

        // 表示StringToUserPropertyEditor可以将String转化成User类型，在Spring源码中，如果发现当前对象是String，而需要的类型是User，就会使用该PropertyEditor来做类型转化
        propertyEditorMap.put(User.class, StringToUserEditor.class);
        customEditorConfigurer.setCustomEditors(propertyEditorMap);
        return customEditorConfigurer;

    }
}
